<?php

/**
 * Свой простой класс для отладки
 *
 * @package mumak
 * @subpackage core
 */
class RL_Debug
{

	/**
	 * уровень severity, при возникновении ошибки такого или большего уровня
	 * завершает выполнение скриптов
	 *
	 * @var int
	 */
	private $halt_level;

	/**
	 * Стек сообщений
	 *
	 * @var array
	 */
	private $log;

	/**
	 * Время майлстоуна
	 *
	 * @var float
	 */
	private $_milestone;

	/**
	 * Время последнего майлстоуна
	 *
	 * @var float
	 */
	private $milestone;

	var $is_error;

	var $to_file;

	/**
	 * Флажок показывает, что мы не измеряем моменты времени
	 *
	 * @var bool
	 */
	private $no_microtime;


	public function __construct( $halt_level=0, $to_file=NULL )
	{
		$this->halt_level = $halt_level;
		$this->log = array();
		$this->is_error = array();
		$this->milestone = $this->getMicroTime();
		$this->_milestone = $this->milestone;
		$this->to_file = $to_file;
		$this->Trace("<b>log started.</b>",0);
	}

	/**
	 * вывод лога
	 *
	 * @param string $prefix
	 * @param string $separator
	 * @param string $postfix
	 */
	public function flush( $prefix="<div>Trace log:</div><ul><li>", $separator="</li><li>", $postfix="</li></ul>" )
	{
		$this->trace( "<b>log flushed.</b>",0);
		ob_start();
		echo $prefix;
		$f=0;
		foreach ($this->log as $item) {
			if (!$f) {
				$f=1;
			} else {
				echo $separator;
			}
			echo $item;
		}
		echo $postfix;
		if ($this->to_file) {
			$data = ob_get_contents();
			ob_end_clean();
			$fp = fopen( $this->to_file ,"w");
			fputs($fp,$data);
			fclose($fp);
		}	else {
			ob_end_flush();
		}
		$this->log = array();
	}

	/**
	 * работа с временными отметками
	 *
	 * @return float
	 */
	private function getMicroTime()
	{
		if ($this->no_microtime) {
			return 0;
		}
		list($usec, $sec) = explode(" ",microtime());
		return ((float)$usec + (float)$sec);
	}

	/**
	 * Засекает майлстоун
	 *
	 * @param string $what сообщение
	 * @return float время между последним майлстоуном и этим
	 */
	public function milestone( $what="" )
	{
		if ($this->no_microtime) {
			return 0;
		}

		$m = $this->getMicroTime();
		$diff = $m-$this->milestone;
		$this->Trace( "milestone (".sprintf("%0.4f",$diff)." sec): ".$what, 0 );
		$this->milestone = $m;
		return $diff;
	}

	/**
	 * вывод в лог
	 *
	 * @param string $what сообщение
	 * @param bool $flush вывести ли лог
	 * @return void
	 */
	public function trace( $what, $flush = 0 )
	{
		if (!is_array($this->log)) {
			global $rh;
			return $rh->debug->Trace( $what, $flush );
		}
		if ($this->no_microtime) {
			$this->log[] = "[tick] ".$what;
		}	else {
			$m = $this->getMicroTime();
			$diff = $m-$this->_milestone;
			$this->log[] = sprintf("[%0.4f] ",$diff).$what;
		}
		if ($flush) {
			$this->Flush();
		}
	}

	/**
	 * вывод в лог массива
	 *
	 * @param array $what
	 * @param bool $flush вывести ли лог
	 * @return string
	 */
	public function trace_r( $what, $flush = 0 )
	{
		if (!is_array($this->log)) {
			global $rh;
			return $rh->debug->trace_r( $what, $flush );
		}
		ob_start();
		print_r($what);
		$result = ob_get_contents();
		//die(sad);
		ob_end_clean();
		$this->Trace("<b><a href=# onclick='var a=document.getElementById(\"__tracediv".substr(md5($result),0,6)."\");a.style.display=(a.style.display==\"none\"?\"block\":\"none\"); return false;'>Trace recursive</a></b><div style='padding-left:60px; display:none' id='__tracediv".substr(md5($result),0,6)."'><pre style='color:#444444; font:11px Tahoma;margin:0'>".$result."</pre><b><a href=# onclick='var a=document.getElementById(\"__tracediv".substr(md5($result),0,6)."\");a.style.display=(a.style.display==\"none\"?\"block\":\"none\"); return false;'>Hide trace recursive</a></b></div>", $flush);
		return "<pre>".$result."</pre>";
	}

	/**
	 * не пуст ли лог ошибок
	 *
	 * @param int $error_level
	 * @return bool
	 */
	public function isError( $error_level = 1 )
	{
		return isset($this->is_error[ $error_level ]);
	}

	/**
	 * добавить в лог запись об ошибке и возможно умереть
	 *
	 * @param string $msg
	 * @param int $error_level
	 * @return mixed
	 */
	public function error( $msg, $error_level = 1 )
	{
		if (!is_array($this->log)) {
			global $rh;
			return $rh->debug->error( $msg, $error_level );
		}
		$this->trace( "<span style='font-weight:bold; color:#ff4000;'>ERROR [".str_pad(str_repeat("!", $error_level ),5,".")."]: ".$msg."</span>", 0 );
		for ($e=$error_level; $e>=0; $e--) {
			$this->is_error[ $e ]=1;
		}
		if ($this->isError($this->halt_level)) {
			$this->halt();
		}
	}

	/**
	 * Вывести дамп переменной и возможно умереть
	 *
	 * @param mixed $msg
	 * @param int $error_level
	 * @return mixed
	 */
	public function error_r( $msg, $error_level = 1 )
	{
		if (!is_array($this->log))
		{
			global $rh;
			return $rh->debug->error_r( $msg, $error_level );
		}
		ob_start();
		print_r($msg);
		$result = ob_get_contents();
		ob_end_clean();
		return $this->error( "<pre>".htmlspecialchars($result)."</pre>", $error_level );
	}

	/**
	 * умереть, тихо или громко
	 *
	 * @param bool $flush вывести ли лог
	 */
	public function halt( $flush = 1 )
	{
		header("Content-Type: text/html; charset=windows-1251");
		if ($flush) {
			$this->flush();
		}
		die("prematurely dying.");
	}


	// EOC{ Debug } 
}

